#include "FKClientManager.h"

#include <QTcpSocket>
#include <QByteArray>
#include <QDataStream>

#include "FKPacker.h"
#include "FKClientData.h"
#include "FKClient.h"
#include "FKEvent.h"
#include "FKMessage.h"

#include "FKLogger.h"

FKClientManager::FKClientManager(QTcpSocket *socket, QObject *parent):QObject(parent){
    FK_CBEGIN
    if(!socket)socket=new QTcpSocket;
    _socket=socket;
    _socket->setParent(this);
    _client=0;
    _blockSize=0;
    _sender=0;
    connect(_socket,SIGNAL(readyRead()),SLOT(readData()));
    connect(_socket,SIGNAL(disconnected()),SLOT(socketDisconnected()));
    connect(&_deletingTimer,SIGNAL(timeout()),SLOT(deleteLater()));
    FK_CEND
}

FKClientManager::~FKClientManager(){
    FK_DEND
    _socket->disconnectFromHost();
    FK_DEND
}

void FKClientManager::socketDisconnected(){
    if(_client)_client->setDisconnected();
    emit disconnected(this);
}

void FKClientManager::startDeletingTimer(int latency){
    _deletingTimer.start(latency);
}

void FKClientManager::stopDeletingTimer(){
    _deletingTimer.stop();
}

QTcpSocket* FKClientManager::socket(){
    return _socket;
}

void FKClientManager::setClient(FKClient *client){
    _client=client;
    if(client)client->setConnected();
    emit clientSetted(client);
}

void FKClientManager::readData(){
    forever{
        if(!_blockSize && !readBlockSize())return;
        if(!readMessageData())return;
    }
}

bool FKClientManager::readBlockSize(){
    if(_socket->bytesAvailable()>=(qint64)sizeof(qint32)){
//        FK_MLOG(QString::number(_socket->bytesAvailable()));
//        return false;
//        bool t;
//        _blockSize=_socket->read(sizeof(qint32)).toInt(&t);
        QDataStream stream(_socket);
        stream.setVersion(QDataStream::Qt_5_0);
        stream>>_blockSize;
        if(!_blockSize){
            FK_MLOG("error reading size of block")
            return false;
        }
        return true;
    }
    return false;
}

bool FKClientManager::readMessageData(){
    if(_socket->bytesAvailable()>=_blockSize){
        char* tmp=0;
        QByteArray data(tmp,_blockSize);
        QDataStream stream(_socket);
        stream.setVersion(QDataStream::Qt_5_0);
        stream>>data;
        parseMessageData(data);
        _blockSize=0;
        return true;
    }else{
        return false;
    }
}

void FKClientManager::parseMessageData(QByteArray data){
    FKSystemObject* obj=0;
    QString messageType(FKPacker::unpack(data,obj));
    if(messageType==FKPacker::genClient){
        FKClientData* client=qobject_cast<FKClientData*>(obj);
        if(client){
            emit genClientRequested(client->clientName(),client->password(),client->validator(),this);
        }else{
            emit message(QString("error parsing genClient data message"), this);
        }
        obj->deleteLater();
    }else if(messageType==FKPacker::clientRequest){
        FKClientData* client=qobject_cast<FKClientData*>(obj);
        if(client){
            emit clientRequested(client->clientName(),client->password(),this);
        }else{
            emit message(QString("error parsing clientRequest data message"),this);
        }
        obj->deleteLater();
    }else if(messageType==FKPacker::client){
        FKClient* client=qobject_cast<FKClient*>(obj);
        if(client){
            setClient(client);
        }else{
            emit message(QString("error parsing client data message"),this);
        }
    }else if(messageType==FKPacker::message){
        FKMessage* msg=qobject_cast<FKMessage*>(obj);
        if(msg){
            emit message(msg->message().toString());
        }else{
            emit message(QString("error parsing Message data message"),this);
        }
        obj->deleteLater();
    }else if(messageType==FKPacker::action){
        if(_client){
            FKEvent* action=qobject_cast<FKEvent*>(obj);
            if(action){
                if(action->client()==_client->getID()){
                    emit gotAction(action);
                }else{
                    emit message(QString("client check failed"),this);
                    obj->deleteLater();
                }
            }else{
                emit message(QString("error parsing action data"),this);
                obj->deleteLater();
            }
        }else{
            emit message(QString("cannot read action before client created"),this);
            obj->deleteLater();
        }
    }else if(messageType==FKPacker::event){
        if(_client){
            FKEvent* event=qobject_cast<FKEvent*>(obj);
            if(event){
//                FK_MLOGV("got event",event->subject())
                emit gotEvent(event);
            }else{
                emit message(QString("error parsing event data"),this);
                obj->deleteLater();
            }
        }else{
            emit message(QString("cannot read event before client created"),this);
            obj->deleteLater();
        }
    }else if(messageType==FKPacker::error){
        emit message(QString("packer error"),this);
        obj->deleteLater();
    }else if(messageType==FKPacker::file){
        FKMessage* msg=qobject_cast<FKMessage*>(obj);
        if(msg){
            emit fileMessage(msg->message());
        }else{
            emit message(QString("error parsing File data message"),this);
        }
        obj->deleteLater();
    }else if(messageType==FKPacker::interruptFile){
        FKMessage* msg=qobject_cast<FKMessage*>(obj);
        if(msg){
            emit interruptFileMessage(msg->message().toString());
        }else{
            emit message(QString("error parsing File data message"),this);
        }
        obj->deleteLater();
    }else{
        emit message(QString("uncknown message type"),this);
        obj->deleteLater();
    }
}

void FKClientManager::sendData(QByteArray data){
    QDataStream stream(_socket);
    stream.setVersion(QDataStream::Qt_5_0);
    stream<<data;
}

//void FKClientManager::setFileSender(FKFileSender* s){
//    _sender=s;
//}

QByteArray FKClientManager::preserveData(QByteArray data){
    QByteArray preserved;
    QDataStream stream(&preserved,QIODevice::ReadWrite);
    stream.setVersion(QDataStream::Qt_5_0);
//    qint32 size=data.size();
//    stream<<size;
    stream<<data;
    return preserved;
}

void FKClientManager::sendMessage(QString message){
    FKMessage m(message);
    QByteArray data(preserveData(FKPacker::pack(FKPacker::message,&m)));
    sendData(data);
}

void FKClientManager::sendFileMessage(QVariant message){
    FKMessage m(message);
    QByteArray data(preserveData(FKPacker::pack(FKPacker::file,&m)));
    sendData(data);
}

void FKClientManager::sendInterruptFileMessage(QString message){
    FKMessage m(message);
    QByteArray data(preserveData(FKPacker::pack(FKPacker::interruptFile,&m)));
    sendData(data);
}

FKClient* FKClientManager::client(){
    return _client;
}
